///@file MultiIndex.cpp
///@brief Implementation of the class representing a MultiIndex
///@author Arnaud Duval
///@version 0.0
///@date 2010/04/14


#include "MultiIndex.h"
#include <assert.h>
#include <cstring>
#include <cmath>

///@brief Default constructor
MultiIndex::MultiIndex()
{
	card = 0;
}

///@brief Constructor with given size
///@param c cardinality of multi-index
MultiIndex::MultiIndex(int c)
{
	assert(c > 0);
	card = c;
	a = new int[c];
}

///@brief Copy constructor
///@param m MultiIndex object to copy
MultiIndex::MultiIndex(const MultiIndex &m)
{
	card = m.card;
	a = new int[card];
	for(unsigned int i = 0 ; i < card ; i++)
		a[i] = m.a[i];
}

///@brief Copy constructor for temporary object
///@param m pointer to MultiIndex object to copy
MultiIndex::MultiIndex(MultiIndex* m)
{
	card = (*m).card;
	a = new int[card];
	for(unsigned int i = 0 ; i < card ; i++)
		a[i] = (*m).a[i];
}

///@brief Destructor
MultiIndex::~MultiIndex()
{
	if(card > 0)
		delete[] a;
}

///@brief Overload of = operator
///@param m right hand member MultiIndex
MultiIndex& MultiIndex::operator=(const MultiIndex &m)
{
	if(card)
		delete[] a;
	card = m.card;
	a = new int[card];
	for(unsigned int i = 0 ; i < card ; i++)
		a[i] = m.a[i];
	return (*this);
}


///@brief Overload of = operator for temporary object
///@param m Right hand operand
MultiIndex& MultiIndex::operator=(MultiIndex* m)
{
	card = (*m).card;
	a = new int[card];
	for(unsigned int i = 0 ; i < card ; i++)
		a[i] = (*m).a[i];
	return (*this);
}

///@brief Overload of &= operator : copy without size check
///@param m MultiIndex object to copy
MultiIndex& MultiIndex::operator&=(const MultiIndex & m)
{
	if(!m.card)
	{
		if(card)
			delete[] a;
		card = 0;
	}
	else
	{
		if(m.card != card)
		{
			if(card)
				delete[] a;
			a = new int[card = m.card];
		}
		memcpy(a, m.a, m.card*sizeof(int));
	}
	return (*this);
}

///@brief Overload of [] operator : direct access to MultiIndex components
///@param i index of returned component
int& MultiIndex::operator[](unsigned int i) const
{
	assert((i >=1)&&(i <= card));
	return a[i-1];
}

///@brief Swap two components
///@param i1 index of first component
///@param i2 index of second component
void MultiIndex::Swap(unsigned int i1, unsigned int i2)
{
	assert((i1 > 0)&&(i1 <= card));
	assert((i2 > 0)&&(i2 <= card));
	int temp = a[i1-1];
	a[i1-1] = a[i2-1];
	a[i2-1] = temp;
}

///@brief Sort values using Bubble sort algorithm
void MultiIndex::BubbleSort()
{
	assert(card > 0);
	bool permut = true;
	while(permut)
	{
		permut = false;
		for(unsigned int i = 1 ; i < card ; i++)
		{
			if(a[i-1] > a[i])
			{
				int temp = a[i];
				a[i] = a[i-1];
				a[i-1] = temp;
				permut = true;
			}
		}
	}
}

///@brief Return q-norm of MultiIndex
///@param q Value of q adopted for the norm
double MultiIndex::qNorm(double q)
{
	assert((q >= 0.)&&(q <= 1.));
	double res = 0.;
	for(unsigned int i = 0 ; i < card ; i++)
		res += pow(a[i], q);
	res = pow(res, 1./q);
	return res;
}

///@brief Return qw-norm of MultiIndex
///@param q Value of q adopted for the norm
///@param w Vector of weigths
double MultiIndex::qwNorm(double q, Vector w)
{
	assert((q >= 0.)&&(q <= 1.));
	assert(w.Dim() == card);
	double res = 0.;
	for(unsigned int i = 0 ; i < card ; i++)
		res += pow(fabs(w[i+1]*a[i]), q);
	res = pow(res, 1./q);
	return res;
}

///@brief Return cardinality of MultiIndex
unsigned int MultiIndex::Cardinality()
{
	return card;
}

///@brief Overload of << operator
///@param s out stream
///@param m Multiindex object to put in the out stream
std::ostream& operator<<(std::ostream &s, const MultiIndex& m)
{
	for(unsigned int i = 0 ; i < m.card ; i++)
		s << m.a[i] << "\t";
	return s;
}

///@brief Overload of == operator
///@param m1 left hand operand MultiIndex
///@param m2 right hand operand MultiIndex
bool operator==(const MultiIndex& m1, const MultiIndex& m2)
{
	assert(m1.card == m2.card);
	for(unsigned int i = 0; i < m1.card ; i++)
	{
		if(m1.a[i] != m2.a[i])
			return false;
	}
	return true;
}